package cn.spike.rockcc.service.impl;

import cn.spike.rockcc.domain.*;
import cn.spike.rockcc.dto.CourseDto;
import cn.spike.rockcc.dto.CourseEsDto;
import cn.spike.rockcc.dto.RedisOrderDto;
import cn.spike.rockcc.dto.StationDto;
import cn.spike.rockcc.errorenum.GlobalExceptionCode;
import cn.spike.rockcc.exception.BusinessException;
import cn.spike.rockcc.feign.MediaFeignClient;
import cn.spike.rockcc.feignclient.SearchFeignClient;
import cn.spike.rockcc.mapper.*;
import cn.spike.rockcc.result.JSONResult;
import cn.spike.rockcc.service.ICourseDetailService;
import cn.spike.rockcc.service.ICourseService;
import cn.spike.rockcc.service.ICourseUserLearnService;
import cn.spike.rockcc.util.AssertUtil;
import cn.spike.rockcc.vo.CourseDataVo;
import cn.spike.rockcc.vo.CourseItemVo;
import cn.spike.rockcc.vo.CourseVo;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.client.producer.SendStatus;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.messaging.Message;
import org.springframework.messaging.support.MessageBuilder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.crypto.Data;
import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author spike
 * @since 2023-03-11
 */
@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {

    @Autowired
    private CourseMapper courseMapper;

    @Autowired
    private TeacherMapper teacherMapper;

    @Autowired
    private CourseDetailMapper courseDetailMapper;

    @Autowired
    private CourseMarketMapper marketMapper;

    @Autowired
    private CourseResourceMapper resourceMapper;

    @Autowired
    private CourseSummaryMapper summaryMapper;

    @Autowired
    private SearchFeignClient searchFeignClient;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private CourseChapterMapper courseChapterMapper;

    @Autowired
    private MediaFeignClient mediaFeignClient;

    @Autowired
    private ICourseUserLearnService courseUserLearnService;

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;


    /**
     * 点击课程详情的业务
     * @param id
     * @return private Course course;
     *         private CourseMarket courseMarket;
     *         private List<CourseChapter> courseChapters;
     *         private List<Teacher> teachers;
     *         private CourseDetail courseDetail;
     *         private CourseSummary courseSummary;
     */
    @Override
    public CourseVo getCourse(Long id) {
        Course course = super.selectById(id);
        AssertUtil.isNotNull(course,GlobalExceptionCode.NOT_COURSE_EXCEPTION);
        AssertUtil.isEquals(course.getStatus(),Course.COURSE_ONLINE,GlobalExceptionCode.NOT_COURSE_EXCEPTION);
        CourseMarket courseMarket = marketMapper.selectById(id);
        Wrapper<CourseChapter> wrapper =new EntityWrapper<>();
        wrapper.eq("course_id",id);
        List<CourseChapter> courseChapters = courseChapterMapper.selectList(wrapper);
        List<Long> ids = courseMapper.selectTeacherIdByCourseId(id);
        List<Teacher> teachers = teacherMapper.selectBatchIds(ids);
        CourseDetail courseDetail = courseDetailMapper.selectById(id);
        CourseSummary courseSummary = summaryMapper.selectById(id);

        Map<Long, CourseChapter> courseChapterMap = courseChapters.stream().
                collect(Collectors.toMap(CourseChapter::getId, courseChapter -> courseChapter));

        JSONResult jsonResult = mediaFeignClient.getMediaByCourseId(id);
        AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCode.MEDIA_SERVER_EXCEPTION);

        List<MediaFile> mediaFiles = JSON.parseArray(JSON.toJSONString(jsonResult.getData()), MediaFile.class);
        if(mediaFiles != null){
            mediaFiles.forEach(mediaFile -> {
                CourseChapter courseChapter = courseChapterMap.get(mediaFile.getChapterId());
                if(courseChapter!=null){
                    mediaFile.setFileUrl("");
                    courseChapter.getMediaFileList().add(mediaFile);
                }
            });
        }

        return new CourseVo(course,courseMarket,courseChapters,teachers,courseDetail,courseSummary);
    }

    /**
     * 用户获取mediaUrl的接口
     * @param id
     * @return String
     */
    @Override
    public String getForUser(Long id) {
        JSONResult jsonResult = mediaFeignClient.getMediaById(id);
        //如果为false 说明远程调用失败 - media服务异常
        AssertUtil.isTrue(jsonResult.isSuccess(),GlobalExceptionCode.MEDIA_SERVER_EXCEPTION);
        //接收返回数据
        MediaFile mediaFile = JSON.parseObject(JSON.toJSONString(jsonResult.getData()), MediaFile.class);
        //如果为null - 说明没有找到该media信息
        AssertUtil.isNotNull(mediaFile,GlobalExceptionCode.NOT_MEDIA_EXCEPTION);
        //找出视频对应的courseMarket信息
        CourseMarket courseMarket = marketMapper.selectById(mediaFile.getCourseId());
        //如果courseMarket的charge属性为1 - 说明免费
        if(courseMarket.getCharge()==1)return mediaFile.getFileUrl();
        //如果不免费 - 但是该media为是看 - 说明可以看
        if(mediaFile.getFree())return mediaFile.getFileUrl();

        // TODO 获取登陆人id
        Long loginId = 3L;
        Wrapper<CourseUserLearn> wrapper = new EntityWrapper<>();
        wrapper.eq("login_id",loginId).and().eq("course_id",mediaFile.getCourseId());
        //找到该用户和该课程的购买信息
        CourseUserLearn courseUserLearn = courseUserLearnService.selectOne(wrapper);
        //如果为空 - 说明用户并未购买该course
        AssertUtil.isNotNull(courseUserLearn,GlobalExceptionCode.NO_BUY_COURSE_EXCEPTION);
        //如果用户购买了course - 判断是否已过过期时间End_Time
        boolean before = new Date().before(courseUserLearn.getEndTime());
        //如果已经过期 - 响应问题
        AssertUtil.isTrue(before,GlobalExceptionCode.COURSE_TIME_OUT_BUY_EXCEPTION);
        return "";
    }

    /**
     * 订单页面 - 获取订单信息
     * @param ids
     * @return
     */
    @Override
    public CourseDataVo orderdata(String ids) {
        String[] arrIds = ids.split(",");
        List<Course> courses = super.selectBatchIds(Arrays.asList(arrIds));
        AssertUtil.isEquals(arrIds.length,courses.size(),GlobalExceptionCode.COURSE_ID_EXCEPTION);
        List<CourseMarket> courseMarkets = marketMapper.selectBatchIds(Arrays.asList(arrIds));

        List<CourseItemVo> courseInfos = new ArrayList<>();
        BigDecimal totalAmount = new BigDecimal(0);
        for (int i = 0; i < arrIds.length; i++){
            courseInfos.add(new CourseItemVo(courses.get(i),courseMarkets.get(i)));
            totalAmount = totalAmount.add(courseMarkets.get(i).getPrice());
        }
        return new CourseDataVo(courseInfos,totalAmount);
    }

    @Override
    public CourseDataVo killInfo(String orderNo) {
        Object o = redisTemplate.opsForValue().get(orderNo);
        AssertUtil.isNotNull(o,GlobalExceptionCode.REDIS_ORDER_NOT_FOUND);
        RedisOrderDto redisOrderDto = (RedisOrderDto) o;
        CourseDataVo courseDataVo = orderdata(redisOrderDto.getCourseId().toString());
        courseDataVo.setTotalAmount(redisOrderDto.getAmount());
        return courseDataVo;
    }


    /**
     * 1.添加t_course
     * 2.添加t_course_detail
     * 3.添加t_course_market
     * 4.添加t_course_resource
     * 5.添加t_course_summary
     * 6.添加t_course_teacher
     * @param dto
     */
    @Override
    @Transactional
    public void save(CourseDto dto) {
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        checkDto(dto);

        StringBuffer tNames = new StringBuffer();
        List<Teacher> teachers = teacherMapper.selectBatchIds(dto.getTeacherIds());
        for (Teacher teacher : teachers) tNames.append(teacher.getName()).append(",");
        String teacherNames = tNames.substring(0,tNames.length()-1);
        course.setTeacherNames(teacherNames);
        course.setId(1L);
        course.setStatus(Course.COURSE_OFFLINE);
        //1.添加t_course
        courseMapper.insert(course);
        Long courseId = course.getId();
        //2.添加t_course_detail
        courseDetail.setId(courseId);
        courseDetailMapper.insert(courseDetail);
        //3.添加t_course_market
        courseMarket.setId(courseId);
        marketMapper.insert(courseMarket);
        //4.添加t_course_resource
        courseResource.setCourseId(courseId);
        resourceMapper.insert(courseResource);
        //5.添加t_course_summary
        CourseSummary courseSummary = new CourseSummary();
        courseSummary.setId(courseId);
        summaryMapper.insert(courseSummary);
        //6.添加t_course_teacher
        courseMapper.insertCourseAndTeacher(courseId,dto.getTeacherIds());

    }

    /**
     * 课程发布的业务
     * @param id
     * 上架 - 添加进es - 发送站内信
     */
    @Override
    @Transactional
    public void onLineCourse(Long id) {
        CourseEsDto courseEsDto = new CourseEsDto();
        Course course = courseMapper.selectById(id);
        AssertUtil.isEquals(Course.COURSE_OFFLINE,course.getStatus(),"请勿重复发布");
        course.setStatus(Course.COURSE_ONLINE);
        course.setOnlineTime(new Date());

        CourseMarket courseMarket = marketMapper.selectById(id);
        CourseSummary courseSummary = summaryMapper.selectById(id);

        BeanUtils.copyProperties(course,courseEsDto);
        BeanUtils.copyProperties(courseMarket,courseEsDto);
        BeanUtils.copyProperties(courseSummary,courseEsDto);
        String charge = courseMarket.getCharge()==1?"免费":"收费";
        courseEsDto.setCharge(charge);
        JSONResult result = searchFeignClient.save(courseEsDto);
        AssertUtil.isTrue(result.isSuccess(), GlobalExceptionCode.SEARCH_EXCEPTION);


        courseMapper.updateById(course);

        //发送站内信 - 投递消息
        String content = "惊喜惊喜，期待已久的课程 %s 发布了,<a href='http://www.itsource.cn?courseId=%s'>点我</a>快速尝鲜。";
        content = String.format(content,course.getName(),course.getId());
        StationDto station = new StationDto();
        station.setTitle("课程发布");
        station.setContent(content);
        station.setType("系统消息");
        List<Long> userIds = new ArrayList<>();
        userIds.add(1L);
        userIds.add(2L);
        userIds.add(3L);
        station.setUserIds(userIds);
        Message<String> message = MessageBuilder.withPayload(JSON.toJSONString(station)).build();
        SendResult sendResult = rocketMQTemplate.syncSend("course-topic:course-publish", message);
        AssertUtil.isTrue(sendResult.getSendStatus() == SendStatus.SEND_OK,
                GlobalExceptionCode.STATION_MQ_EXCEPTION);
    }



    private void checkDto(CourseDto dto){
        Course course = dto.getCourse();
        CourseDetail courseDetail = dto.getCourseDetail();
        CourseMarket courseMarket = dto.getCourseMarket();
        CourseResource courseResource = dto.getCourseResource();
        List<Long> teacherIds = dto.getTeacherIds();
        AssertUtil.isNotNull(course,"课程信息有误");
        AssertUtil.isNotNull(courseDetail,"课程详情信息有误");
        AssertUtil.isNotNull(courseMarket,"课程售卖信息有误");
        AssertUtil.isNotNull(courseResource,"课件有误");
        AssertUtil.isNotNull(teacherIds,"课程讲师有误");
    }
}
